HDU 5772 String problem(最大权闭合子图)

题意:

$懒得翻译题目了 - -$

分析:

$最大权闭合子图详细见胡波涛的论文$
$建图就源向正权点连边,容量是正权,负权就负权点向汇连边,容量是负权的绝对值$
$对于原图中依赖关系,保留在网络流图中,容量是INF$
$答案是\sum 正权-最小割$


本题,官方题解写的很清楚了

代码:

//
//  Created by TaoSama on 2016-08-02
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
const int M = 1e6 + 10;

//必须添加超源超汇 0->s n+1->t
//特判起终点相同的情况 -> WA
struct Edge {
    int v, nxt, cap, flow;
} edge[M];
int head[N], cnt;

void addEdge(int u, int v, int c1) {
    edge[cnt] = {v, head[u], c1, 0};
    head[u] = cnt++;
    edge[cnt] = {u, head[v], 0, 0};
    head[v] = cnt++;
}

int lev[N], cur[N];
bool bfs(int s, int t) {
    queue<int> q;
    memset(lev, 0, sizeof lev);
    q.push(s);  lev[s] = 1;
    while(q.size() && !lev[t]) {
        int u = q.front(); q.pop();
        for(int i = head[u]; ~i; i = edge[i].nxt) {
            int v = edge[i].v;
            if(edge[i].cap > edge[i].flow && !lev[v]) {
                lev[v] = lev[u] + 1;
                q.push(v);
            }
        }
    }
    return lev[t];
}

int dfs(int u, int t, int delta) {
    if(u == t || !delta) return delta;
    int ret = 0;
    for(int i = cur[u]; ~i; i = edge[i].nxt) {
        int v = edge[i].v;
        if(edge[i].cap > edge[i].flow && lev[v] == lev[u] + 1) {
            int d = dfs(v, t, min(delta, edge[i].cap - edge[i].flow));
            cur[u] = i;
            ret += d; delta -= d;
            edge[i].flow += d;
            edge[i ^ 1].flow -= d;

            if(delta == 0) return ret;
        }
    }
    lev[u] = 0;
    return ret;
}

int dinic(int s, int t) {
    int ret = 0;
    while(bfs(s, t)) {
        for(int i = s; i <= t; ++i) cur[i] = head[i];
        ret += dfs(s, t, INF);
    }
    return ret;
}

const int C = 100;
int n, a[C], b[C];
char str[C];

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    int T; scanf("%d", &T);
    while(T--) {
        scanf("%d%s", &n, str + 1);
        for(int i = 0; i <= 9; ++i) scanf("%d%d", a + i, b + i);

        cnt = 0; memset(head, -1, sizeof head);
        int s = 0, t = n * n + n + 10 + 1;

        //w_ij: 1~n^2    s_i: n^2+1 ~ n^2+n
        //10: n^2+n+1 ~ n^2+n+10

        int sum = 0;
        int delta[] = {0, n * n, n* n + n};
        for(int i = 0; i < 10; ++i)
            addEdge(delta[2] + i + 1, t, -(a[i] - b[i])); //10 -> t
        for(int i = 1; i <= n; ++i) {
            addEdge(delta[1] + i, t, a[str[i] - '0']); //s_i -> t
            addEdge(delta[1] + i, delta[2] + str[i] - '0' + 1, INF); //s_i -> 10
            for(int j = 1; j <= n; ++j) {
                int w; scanf("%d", &w);
                sum += w;
                addEdge(s, (i - 1) * n + j, w); //s -> w_ij
                if(i == j) continue;
                addEdge((i - 1) * n + j, delta[1] + i, INF); //w_ij -> s_i
                addEdge((i - 1) * n + j, delta[1] + j, INF); //w_ij -> s_j
            }
        }

        static int kase = 0;
        printf("Case #%d: %d\n", ++kase, sum - dinic(s, t));
    }

    return 0;
}